package com.fw4j.jdbc.factory;

import java.io.FileNotFoundException;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.SQLException;

import com.fw4j.jdbc.annotation.Dao;
import com.fw4j.jdbc.annotation.Query;
import com.fw4j.jdbc.annotation.Where;
import com.fw4j.jdbc.datasource.pool.DataSources;
import com.fw4j.jdbc.engine.TransactionCallback;
import com.fw4j.jdbc.exception.InstanceException;
import com.fw4j.jdbc.tools.CreateDao;


/**
 * @author 穆仁超
 * 创建Dao类工厂
 * 日期 2013-12-27 16:34
 * 我的QQ群：32894018
 */
public class DaoFactory {
	private static java.sql.Connection conn = null;
	public static synchronized void  transaction(TransactionCallback callback){
		try {
			conn = DataSources.getInstance().getConnection();
			conn.setAutoCommit(false);
			callback.invoke();
			conn.commit();
		} catch (SQLException e) {
			try {
				conn.rollback();
			} catch (SQLException e1) {
				e1.printStackTrace();
			}
			e.printStackTrace();
		}
		try {
			conn.close();
			conn = null;
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
	
	public static synchronized <T> T getSynConnectInstance(Class<T> cl) throws InstanceException{
		Annotation[] ans = cl.getAnnotations();
		boolean isDao = false;
		Class daoClass = Object.class;
		for(Annotation a : ans){
			if(a instanceof Dao){
				isDao = true;
				Dao d= (Dao)a;
				daoClass = d.value();
			}
		}//end for
		if(!isDao){
			throw new InstanceException("class "+cl.getName() + "is not dao");
		}//end if
		StringBuffer _class_ = new StringBuffer("fw4j_"); 
		_class_.append(cl.getSimpleName());
		String className = _class_.toString();
		CreateDao dao = null;
		try {
			dao = new CreateDao();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
		Object instance = dao.getInstance(className.toString());
		if(instance != null){
			try {
				instance.getClass().getMethod("setConnection",java.sql.Connection.class).invoke(instance, conn);
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			} catch (IllegalArgumentException e) {
				e.printStackTrace();
			} catch (InvocationTargetException e) {
				e.printStackTrace();
			} catch (NoSuchMethodException e) {
				e.printStackTrace();
			} catch (SecurityException e) {
				e.printStackTrace();
			}
			return (T)instance;
		}
		dao.createClass(className,"com/fw4j/jdbc/dao/DaoTemplate", new String[]{cl.getName().replace(".","/")},daoClass);
		Method[] ms = cl.getMethods();
		for(Method m : ms){
			ans = m.getAnnotations();
			if(ans != null){
				StringBuffer sql = new StringBuffer();
				for(Annotation a : ans){
					if(a instanceof Query){
						Query q = (Query)a;
						sql.append(q.value());
					}else if(a instanceof Where){
						Where q = (Where)a;
						sql.append(" where ");
						sql.append(q.value());
					}//end if
				}//end if
				Class[] ptype = m.getParameterTypes();
				Class retype = m.getReturnType();
				String methodName = m.getName();
				if(methodName.startsWith("find")){
					StringBuffer sbpt = new StringBuffer();
					for(Class c : ptype){
						sbpt.append(c.getName().replace(".", "/"));
						sbpt.append(",");
					}
					sbpt.replace(sbpt.lastIndexOf(","), sbpt.length(), "");
					dao.createMethod(retype.getName().replace(".", "/")+" "+methodName+" ("+sbpt.toString()+")");
					dao.addList();
					dao.addString(sql.toString());
					for(int i = 0;i<ptype.length;i++){
						Class pt = ptype[i];
						if(pt != Class.class){
							dao.ListAdd(pt,i);
						}
					}//end for
					dao.callFind(retype);
					dao.endMethod();
				}//end if
				
				if(methodName.startsWith("modify")){
					StringBuffer sbpt = new StringBuffer();
					for(Class c : ptype){
						sbpt.append(c.getName().replace(".", "/"));
						sbpt.append(",");
					}
					sbpt.replace(sbpt.lastIndexOf(","), sbpt.length(), "");
					dao.createMethod(retype.getName().replace(".", "/")+" "+methodName+" ("+sbpt.toString()+")");
					dao.addList();
					dao.addString(sql.toString());
					for(int i = 0;i<ptype.length;i++){
						Class pt = ptype[i];
						if(pt != Class.class){
							dao.ListAdd(pt,i);
						}
					}//end for
					dao.callModify();
					dao.endMethod();
				}//end if
			}//end if
		}//end for
		instance = dao.loadClass();
		try {
			instance.getClass().getMethod("setConnection",java.sql.Connection.class).invoke(instance, conn);
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		}
		return (T)instance;
	}
	
	
	public static <T> T getInstance(Class<T> cl) throws InstanceException{
		Annotation[] ans = cl.getAnnotations();
		boolean isDao = false;
		Class daoClass = Object.class;
		for(Annotation a : ans){
			if(a instanceof Dao){
				isDao = true;
				Dao d= (Dao)a;
				daoClass = d.value();
			}
		}//end for
		if(!isDao){
			throw new InstanceException("class "+cl.getName() + "is not dao");
		}//end if
		StringBuffer _class_ = new StringBuffer("fw4j_"); 
		_class_.append(cl.getSimpleName());
		String className = _class_.toString();
		CreateDao dao = null;
		try {
			dao = new CreateDao();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
		Object instance = dao.getInstance(className.toString());
		if(instance != null){
			return (T)instance;
		}
		dao.createClass(className,"com/fw4j/jdbc/dao/DaoTemplate", new String[]{cl.getName().replace(".","/")},daoClass);
		Method[] ms = cl.getMethods();
		for(Method m : ms){
			ans = m.getAnnotations();
			if(ans != null){
				StringBuffer sql = new StringBuffer();
				for(Annotation a : ans){
					if(a instanceof Query){
						Query q = (Query)a;
						sql.append(q.value());
					}else if(a instanceof Where){
						Where q = (Where)a;
						sql.append(" where ");
						sql.append(q.value());
					}//end if
				}//end if
				Class[] ptype = m.getParameterTypes();
				Class retype = m.getReturnType();
				String methodName = m.getName();
				if(methodName.startsWith("find")){
					StringBuffer sbpt = new StringBuffer();
					for(Class c : ptype){
						sbpt.append(c.getName().replace(".", "/"));
						sbpt.append(",");
					}
					sbpt.replace(sbpt.lastIndexOf(","), sbpt.length(), "");
					dao.createMethod(retype.getName().replace(".", "/")+" "+methodName+" ("+sbpt.toString()+")");
					dao.addList();
					dao.addString(sql.toString());
					for(int i = 0;i<ptype.length;i++){
						Class pt = ptype[i];
						if(pt != Class.class){
							dao.ListAdd(pt,i);
						}
					}//end for
					dao.callFind(retype);
					dao.endMethod();
				}//end if
				
				if(methodName.startsWith("modify")){
					StringBuffer sbpt = new StringBuffer();
					for(Class c : ptype){
						sbpt.append(c.getName().replace(".", "/"));
						sbpt.append(",");
					}
					sbpt.replace(sbpt.lastIndexOf(","), sbpt.length(), "");
					dao.createMethod(retype.getName().replace(".", "/")+" "+methodName+" ("+sbpt.toString()+")");
					dao.addList();
					dao.addString(sql.toString());
					for(int i = 0;i<ptype.length;i++){
						Class pt = ptype[i];
						if(pt != Class.class){
							dao.ListAdd(pt,i);
						}
					}//end for
					dao.callModify();
					dao.endMethod();
				}//end if
			}//end if
		}//end for
		instance = dao.loadClass();
		return (T)instance;
	}
}